package p3.ejemplos;

import java.io.IOException;
import java.net.BindException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

import p3.IServidor;
import p3.IHandler;

/**
 * Servidor Concurrente. 
 * Arranca un hilo por cada petición de servicio.
 * Cada petición esta asociada a un hilo (thread per request) y, dada la forma
 * en la que trabaja el manejador utilizado, también a una conexión (thread per connection).
 * @author JAPF
 *
 */
public class ServidorConcurrente implements IServidor {

	protected int listenPort = 3000;
	ServerSocket server;
	
	/**
	 * Crea el socket servidor y se pone a la espera de peticiones de servicio.
	 * Cuando llega una petición de servicio crea un hilo para que la sirva
	 * y se pone inmediatamente a la espera de la siguiente.
	 */
	public void aceptarConexiones() throws BindException, IOException {
		
		try{

			server = new ServerSocket();
			server.setReuseAddress(true);
			server.bind(new InetSocketAddress(Inet4Address.getLocalHost(), listenPort), 5);

			Socket incomingConnection = null;
			while (true) {
				incomingConnection = server.accept();
				handleConnection(incomingConnection);
			}
		}
		catch(BindException be){
			be.printStackTrace();	
			throw be;
		}
		catch(IOException ioe){
			ioe.printStackTrace();		
			throw ioe;
		}
	}
	
	/**
	 * Interacciona con el socket cliente para enviarle los contenidos
	 * del fichero solicitado. Es un método no bloqueante. 
	 * Retorna en cuanto empieza el servicio. 
	 * @param incomingConection
	 */
	public void handleConnection(Socket socketToHandle){
		new Thread(new WorkerThread(socketToHandle)).start();
	}
	

    class WorkerThread implements Runnable {
    	
    	Socket socketToHandle;
    	IHandler handler;
    	
    	public WorkerThread(Socket socketToHandle){
    		this.socketToHandle = socketToHandle;
    		handler = new FileRequestHandler(socketToHandle);
    	}
    	
    	public void run(){
    		handler.doService();
    	}
    }
    
	public void shutdown(){
		try {
			if (server != null) server.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void finalize(){
		shutdown();
	}

	
	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
       ServidorConcurrente servidor = new ServidorConcurrente();
       servidor.aceptarConexiones();
       
	}

}
